/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package no.ffi.tpm.aik;

import java.io.Serializable;
import java.security.PublicKey;
import java.security.cert.X509Certificate;


/**
 * This class encapsulate an AIK certification request for a PCA.
 * The request consists of the Endorsment certificate (EC), the AIK to be certified, 
 * and a binding between the AIK and the PCA credentials, called idBinding.
 * 
 * @author Federico Mancinie <fma at ffi.no>
 */
public class AIKRequest implements Serializable {
    
    //The endorsment certificate
    private X509Certificate EC;
    
    //The AIK to certify as a PublicKey object
    private PublicKey AIK;
    
    //The raw encoding of the AIK as the TPM stores it
    private byte[] AIKBytes;
    
    //The binding between PCA and AIK
    //It looks like (SHA-1(idpreamble||idhash||tpmAIK)) signed with the AIK
    private byte[] idBinding;
    
    //The data structure containing the AIK which is used to 
    //calculate the AIK hash to be used in the response
    private byte[] tpmAIK;
    
    //The size of the encoded AIK. This can be used to extract the encoded AIK  
    //from the tpmAIK structure, since it is the last of its fields.
    private int AIKSize ;
    
    
    //SHA-1(PCALabel||PCAPublicKey)
    private byte[] idHash;
    
    //(TPMVersion||TPM_ORD_CONST_MAKEID)
    private byte[] idPreamble;
    
    //The name of the PCA given to the TPM
    private byte[] PCALabel;
    
    //The TPM version used in idBinding
    private byte[] version;
    
    //The PCA public key encapsulated in a TPM compatible datastructure
    private byte[] PCAPubKey;
    
    //The length of the PCAPubKey, qhich can be used to extract the modulus
    private int PCAlength;
    
    private byte[] responseTemplate;
    private PCRAttestation PCR;
    
    //This method reconstruct the hash that was signed with the AIK to 
    //generate the IdBinding value. It should correspond to the value one
    //obtains decrypting idBinding with the given AIK
//    public byte[] makeIdHash() {
//
//         byte[] hash = null;
//        ByteArrayOutputStream baout = new ByteArrayOutputStream();
//        DataOutputStream dout = new DataOutputStream(baout);
//        try {
//            //Recreate the HashId=SHA_1(PCAlabel||PCAPubKey)
//            dout.write(this.PCALabel);
//            dout.write(PCAPubKey);
//            dout.flush();
//            
//            byte[] aikID = baout.toByteArray();
//            baout.reset();
//            
//            MessageDigest sha = MessageDigest.getInstance("SHA-1");
//            sha.update(aikID);
//            byte[] aikIDHash = sha.digest();
//            sha.reset();
//
//            //Recreate the IdBinding hash
//            dout.write(this.idPreamble);
//            dout.write(aikIDHash);
//            dout.write(this.tpmAIK);
//            dout.flush();
//            byte[] toHash=baout.toByteArray();
//            sha.update(toHash);
//            hash=sha.digest();            
//
//        } catch (IOException ex) {
//            Logger.getLogger(PCARequest.class.getName()).log(Level.SEVERE, null, ex);
//        } catch (NoSuchAlgorithmException ex) {
//            Logger.getLogger(PCARequest.class.getName()).log(Level.SEVERE, null, ex);
//        }
//        return hash;
//    }
    
    public byte[] buildResponse(byte[] sessKey) {
        byte[] response = this.responseTemplate;
        System.arraycopy(sessKey,0 ,response , 8, sessKey.length);
        /*int keySize=sessKey.length;
        long TPM_ALG_AES_128=6L;
        int TPM_ES_SYM_CBC_PKCS=255;
        
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            int hashLength = md.getDigestLength();
            response = new byte[8 + sessKey.length + hashLength];//key information+key+SHA-1(aikstruct)
            //AlgorithmID
            response[0]= (byte)(TPM_ALG_AES_128 & 0x000000ff); 
	    TPM_ALG_AES_128 >>= 8;
            response[1]= (byte)(TPM_ALG_AES_128 & 0x000000ff); 
	    TPM_ALG_AES_128 >>= 8;
            response[2]= (byte)(TPM_ALG_AES_128 & 0x000000ff); 
	    TPM_ALG_AES_128 >>= 8;
            response[3]= (byte)(TPM_ALG_AES_128 & 0x000000ff); 
	    TPM_ALG_AES_128 >>= 8;
            //Encryptopn scheme
            response[4]= (byte)(TPM_ES_SYM_CBC_PKCS & 0x00ff); 
            TPM_ES_SYM_CBC_PKCS >>= 8;
            response[5]= (byte)(TPM_ES_SYM_CBC_PKCS & 0x00ff); 
            //Length of session key                    
            response[6]= (byte) (keySize & 0x00ff); 
            keySize >>= 8;
	    response[7] = (byte) (keySize & 0x00ff);
            System.arraycopy(sessKey, 0, response, 8, sessKey.length);
            byte[] aikHash = null;
            md.update(this.tpmAIK);
            aikHash = md.digest();
            System.arraycopy(aikHash, 0, response, response.length - hashLength, hashLength);

        } catch (NoSuchAlgorithmException e) {
            // can be ignored since startup checks were OK
        }*/
        return response;
    }
    
    void setAIKSize(int size) {
        AIKSize=size;;
    }

    void setAIK(PublicKey aik) {
        AIK=aik;
    }

    void setAIKStruct(byte[] tpmEncodedAIK) {
        tpmAIK=tpmEncodedAIK;
    }

   

    void setIdBinding(byte[] binding) {
        this.idBinding=binding;
    }

    void setEC(X509Certificate ec) {
       EC=ec;
    }

    void setAIKbytes(byte[] aik) {
        AIKBytes=aik;
    }

    void setPCALabel(byte[] label) {
        PCALabel=label;
    }

    void setVersion(byte[] vers) {
       version=vers;
    }

    /**
     * @return the EC
     */
    public X509Certificate getEC() {
        return EC;
    }

    /**
     * @return the AIK
     */
    public PublicKey getAIK() {
        return AIK;
    }

    /**
     * @return the AIKBytes
     */
    public byte[] getAIKBytes() {
        return AIKBytes;
    }

    /**
     * @return the idBinding
     */
    public byte[] getIdBinding() {
        return idBinding;
    }

    /**
     * @return the tpmAIK
     */
    public byte[] getTpmAIK() {
        return tpmAIK;
    }

    /**
     * @return the AIKSize
     */
    public int getAIKSize() {
        return AIKSize;
    }

 

    /**
     * @return the idHash
     */
    public byte[] getIdHash() {
        return idHash;
    }

    /**
     * @return the idPreamble
     */
    public byte[] getIdPreamble() {
        return idPreamble;
    }

    /**
     * @return the PCALabel
     */
    public byte[] getPCALabel() {
        return PCALabel;
    }

    /**
     * @return the version
     */
    public byte[] getVersion() {
        return version;
    }

    public byte[] verifyIdBinding(byte[] PCAkey){
        return null;
    }

    void setPCAPubKey(byte[] tpmPCAPubKey) {
        this.PCAPubKey=tpmPCAPubKey;
    }

    void setPCALength(int PCALength) {
        PCAlength=PCALength;
    }

    /**
     * @return the PCAPubKey
     */
    public byte[] getPCAPubKey() {
        return PCAPubKey;
    }

    /**
     * @return the PCAlength
     */
    public int getPCAlength() {
        return PCAlength;
    }

    void setResponsePreamble(byte[] responseTemplate) {
        this.responseTemplate=responseTemplate;
    }

    void setPCR(byte[] data,byte[] signature,byte[] nonce) {
        this.PCR=new PCRAttestation(data, signature,nonce);
    }
     
    public PCRAttestation getPCR(){
        return this.PCR;
    }
    
    
}
